con

  _clkfreq = 80_000_000
  _clkmode = xtal1 + pll16x




  TX_PIN        = 30
  BAUDRATE      = 115_200

pub go | i


'  coginit(0, @Entry, 0)

'  repeat
'    waitcnt(0)

  sync_start := cnt + clkfreq*2

  'launch each cog in decending order
  coginit(7, @Entry, i)
  coginit(6, @Entry, i)
  coginit(5, @Entry, i)
  coginit(4, @Entry, i)
  coginit(3, @Entry, i)
  coginit(2, @Entry, i)
  coginit(1, @Entry, i)
  coginit(0, @Entry, i)

  '^^^^  Even though the cogs are launched in decending order, the test is
  '  performed in ascending order (cog 0 tests first with cog 7 testing last)
     
  
dat

        'assembly program to write a bit pattern out to
        'every Hub RAM address and verify it

              org

Entry         waitcnt   sync_start,#0           'syncronization point for all cogs, wait here 'till it's time

              'All cogs are synchronized at this point!


              'Add an additional starting delay here.
              
              'mov       t0,one_sec             '
              'shl       t0,#2
              'add       sync_start,t0


              'Calculate a time period to wait before starting the test so as not to
              'walk all over an adjacent cog's test.
              cogid     cog_num                 

              mov       t0,cog_num
              add       t0,#1
              mov       timer,#0

              mov       t1,one_sec
              shr       t1,#3
                            
:loop         add       timer,t1
              djnz      t0,#:loop

              add       timer,cnt
              waitcnt   timer,#0







:main         mov       a0,#cog_num_str         'a0 = address of string to print              
              call      #Print_Str              'print the Cog number string

              
              mov       acc,cog_num             'get ready to print the cog number
              add       acc,#$30                'add this constant to make the decimal number an ASCII char
              call      #Serout                 'print the number

              
              call      #Do_Test                'Do the test!

              
              mov       acc,#13                 'print a \n
              call      #Serout

              'jmp       #blink_leds            'an alternate end to the test.  Blinks an LED that corresponds with a passed cog.
              jmp       #hang                   'end of the test, stop the cog

                                    
              





              
'================================ Do Test =======================================================================
'       Does the Hub RAM test.  This test writes a pattern out to Hub RAM, reads it back, and compares the results.
'       A total of 4 write/read combinations are performed on each Hub RAM location, excercising each bit of the
'       memory.
       
Do_Test       mov       curr_addy,#0            'setup the test.  Start testing from the beginning of memory.

:loop         mov       t0,#3                   'setup the number of passes for the current memory location.
              mov       t1,pattern              'setup the starting test pattern.

:do_pass      wrlong    t1,curr_addy            'write a test pattern out to Hub RAM
              rdlong    t2,curr_addy            'read the value back out of Hub RAM
              cmp       t2,t1              wz   'compare the written value with the read value
    if_nz     jmp       #Do_test_fail           'if the two are different, the result will be non-zero and the test failed.

              ror       t1,#1                   'rotate the current test pattern
              xor       t1,pattern              'flip the bits of the test pattern to form a new test pattern
              
              djnz      t0,#:do_pass            'do another test pass on the current memory location?

              add       curr_addy,#4            'move on to the next memory location.
              djnz      num_longs,#:loop        'test another memory location, testing from low memory to high memory

              'if we get here, cog's access to Hub RAM passed!

              mov       a0,#pass_str            'setup to print pass string
              call      #Print_str              'print the pass string to the terminal
                            
Do_Test_ret   ret                               'all done, return
              

'================================ Do Test Fail ==================================================================
'       This routine is called when the value read back from Hub RAM differs from what was just written.  This
'       indicates a memory failure.

Do_test_fail  mov       a0,#fail_str            'setup the "fail" string
              call      #Print_str              'print the "fail" string
              jmp       #hang                   'the test failed, hang the cog up!
              

'================================ Hang ==========================================================================
'       Hang the cog's execution.  This routine simply stops the cog.

hang          cogstop  cog_num                  'stop self
              jmp       #hang                   'shouldnt ever have to jump back, but just in case...


'================================ Print String ==================================================================

Print_Str     movd      :strloop,a0
              nop
:strloop      cmp       0-0,#0            wz    'check to see if we have reached our zero-terminator
        

              'xor      outa, #1                'toggle an LED (for debugging)

              movs      :load,a0
              nop
              nop
        if_z  jmp       #Print_Str_ret          'if we have, then jump to the return address
        
:load         mov       acc,0-0                 'load the char into the accumulator for transmission
              call      #Serout                 'send the char
              
              add       a0,#1                   'increment the string address pointer
              movd      :strloop,a0             'set up the next char to be compared
              nop                               'let a few "do-nothing" instructions through to allow the destination
              nop                               'register modificaiton take place.
              jmp       #:strloop               'do it again

Print_Str_ret
              ret

'================================ Serout =======================================================================

Serout        or        outa,out_mask           'set TX_PIN high for serial transmission
              or        dira,out_mask           'Set TX_PIN to output
              mov       bit_cnt,#10             'extra stop bit padding, set up the number of bits to be TXed
              mov       t0,#%1                  'extra stop bit padding
              shl       t0,#8                   'get ready to OR this with the data byte
              or        acc,t0                  'OR it
              shl       acc,#1                  'shift in one start bit

              mov       bit_time,baud           'calc the number of clock ticks for our baud rate
              add       bit_time,cnt            'add to the current system time
              
:bitloop      shr       acc,#1            wc    'put bit to be TXed into carry
              muxc      outa,out_mask           'stick the state of carry to the pin
              waitcnt   bit_time,baud           'wait for the right amount of time
              djnz      bit_cnt,#:bitloop       'do it again until we run out of bits to TX
              
              andn      dira,out_mask           'make the pin an input to let the other cogs have a chance at communicating
Serout_ret    ret


'================================ Blink LEDs ===================================================================
'
'  This little routine blinks one LED on the quickstart board, per cog. This is, cog 0 only blinks
'  LED 0 located on pin P16.  Cog 1 only blinks LED 1 on pin P17 and so on.  This blinks the LEDs in
'  an infinite loop, so real code execution stops upon jumping to this routine.

'  This routine could potentially be used to report back to the Propeller Tester success/failure of each cog.


blink_leds    cogid     t0                      'save the cog's ID in t0, used for determining the LED pin mask
              add       t0,#16                  'starting at pin 16, this is for the Quickstart's LEDs.

              mov       t1,#1                   'setup the pin mask
              shl       t1,t0                   'shift the single bit out
              
              
              or        dira,t1                 'make pin an output

              waitcnt   sync_start,#0           'synchronize the LED blinking in each cog.
                                                'This value was set up near the beginning of the program.

              mov       timer,one_sec           'set up the one second blink timer
              add       timer,cnt               'get the current time
              
:blink        xor       outa,t1                 'toggle pin state
              waitcnt   timer,one_sec           'wait one second
              jmp       #:blink                 'do it again


'================================ Variable Definitions =========================================================


one_sec       long      _clkfreq                'number of clock ticks in one second
sync_start    long      0-0                     'written by the spin init code

num_longs     long      $8000>>2                'the number of longs in Hub RAM
pattern       long      $5555_5555              'the starting bit pattern used to read/write to Hub RAM

out_mask      long      1<<TX_PIN               'output pin mask

'Simple string definitions.  Each character byte is stored as a long to facilitate transmission.
cog_num_str   long      "Cog ", 0
pass_str      long      ": PASS", 0
fail_str      long      ": !!!!  FAIL", 0

baud          long      _clkfreq / BAUDRATE     'number of clock ticks to acheive a specified baud rate


'================================ Uninitialized Cog Variable Definitions =======================================

acc           res       1
bit_time      res       1
bit_cnt       res       1
cog_num       res       1
curr_addy     res       1
timer         res       1

'temporaries
t0            res       1
t1            res       1
t2            res       1
t3            res       1

'return registers
r0            res       1
r1            res       1

'argument registers
a0            res       1
a1            res       1